// [[ OnflowGenerator File UUID: 607892aa89114784a3a5e70844ca80b7  ]]
package com.itdct.onflow.system.dict.service

import com.itdct.onflow.core.constant.CommonString
import com.itdct.onflow.core.constant.ReturnCode
import com.itdct.onflow.core.extend.*
import com.itdct.onflow.core.vo.KeyLabelValueVo
import com.itdct.onflow.core.vo.RespPageVo
import com.itdct.onflow.core.vo.RespVo
import com.itdct.onflow.system.common.base.BaseSysService
import com.itdct.onflow.system.common.context.Context
import com.itdct.onflow.system.common.extend.dict
import com.itdct.onflow.system.dict.constant.DictRedisKey
import com.itdct.onflow.system.dict.entity.SysDictEntity
import com.itdct.onflow.system.dict.global.DictLock
import com.itdct.onflow.system.dict.manager.SysDictManager
import com.itdct.onflow.system.dict.mapper.SysDictMapper
import com.itdct.onflow.system.dict.qo.SysDictEditQo
import com.itdct.onflow.system.dict.qo.SysDictSearchQo
import com.itdct.onflow.system.dict.vo.SysDictDetailVo
import com.itdct.onflow.system.dict.vo.SysDictListVo
import org.springframework.data.redis.core.RedisTemplate
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

/**
 * @author DCTANT
 * @date 2025-09-01 14:43:30
 * @version 1.0
 * @description 系统字典服务
 */
@Service
class SysDictService(
    val sysDictMapper: SysDictMapper,
    val sysDictManager: SysDictManager,
    val redisTemplate: RedisTemplate<String, Any>
) : BaseSysService() {

    @Transactional(rollbackFor = [Exception::class])
    fun add(qo: SysDictEditQo, context: Context): RespVo<Long> {
        val addEntity = qo.toEntity(SysDictEntity::class.java)

        val parentId = qo.parentId ?: 0L
        if (parentId == 0L) {
            addEntity.codePath = qo.code!!
        } else {
            val parentDict = sysDictMapper.selectByIdEx(parentId)
            addEntity.codePath = parentDict.codePath + "/" + qo.code
        }

        val id = sysDictMapper.insertEx(addEntity)
        return success(id)
    }

    @Transactional(rollbackFor = [Exception::class])
    fun update(qo: SysDictEditQo, context: Context): RespVo<Unit> {
        val updateEntity = sysDictMapper.selectByIdEx(qo.id)
        qo.injectValue(updateEntity)

        val parentId = qo.parentId ?: 0L
        if (parentId == 0L) {
            updateEntity.codePath = qo.code!!
        } else {
            val parentDict = sysDictMapper.selectByIdEx(parentId)
            updateEntity.codePath = parentDict.codePath + "/" + qo.code
        }

        sysDictMapper.updateEx(updateEntity)
        return success()
    }

    fun delete(qo: SysDictEditQo, context: Context): RespVo<Unit> {
        val ids = qo.ids ?: fail(ReturnCode.LACK_PARAM, CommonString.REQUIRE_DELETE_ID_LIST)
        val deleteEntities = sysDictMapper.selectByIdsEx(ids)
        sysDictMapper.deleteBatchEx(deleteEntities)
        return success()
    }

    fun detail(qo: SysDictSearchQo, context: Context): RespVo<SysDictDetailVo> {
        val id = qo.id ?: fail(ReturnCode.LACK_PARAM, CommonString.REQUIRE_ID)
        val vo = sysDictMapper.findById(id) ?: fail(CommonString.ENTITY_NOT_FOUND_USAGE("系统字典", id))
        return success(vo.dict())
    }

    fun page(qo: SysDictSearchQo, context: Context): RespPageVo<SysDictListVo> {
        startPage(context)
        val pageData = sysDictMapper.findByList(qo).dict()
        val listVoMap = pageData.associateBy { it.id }

        clearPage(context)
        val sysDictSearchQo = SysDictSearchQo()
        sysDictSearchQo.exceptRoot = true
        val findByList = sysDictMapper.findByList(sysDictSearchQo).dict()
        val notRootListVoMap = findByList.associateBy { it.id }

        val totalMap = HashMap<Long, SysDictListVo>()
        totalMap.putAll(listVoMap)
        totalMap.putAll(notRootListVoMap)

        for (sysDictListVo in findByList) {
            val parentId = sysDictListVo.parentId
            totalMap[parentId]?.also {
                it.children.add(sysDictListVo)
                it.children.sortBy { it.sort }
            }
        }
        return successPage(pageData)
    }

    fun chooseDictList(qo: SysDictSearchQo, context: Context): RespVo<List<KeyLabelValueVo>> {
        var codePath = qo.codePath
        val vos = ArrayList<KeyLabelValueVo>()
        if (codePath.isNullOrBlank()) {
            fail(ReturnCode.LACK_PARAM, CommonString.LACK_PARAM)
        } else {
            if (!codePath.endsWith("/")) {
                codePath += "/"
            }
            val dictEntities = sysDictMapper.findByCodePath(codePath, qo.code) as List<SysDictEntity>
            if (dictEntities.isEmpty()) {
                fail(ReturnCode.NOT_FOUND_ERROR, "无法找到该code对应值，code值为：${qo.codePath}")
            } else {
                dictEntities.forEach {
                    val vo = KeyLabelValueVo()
                    vo.key = it.code
                    vo.label = it.name
                    vo.value = it.code
                    vos.add(vo)
                }
            }
        }
        return success(vos)
    }

    fun refreshDict(context: Context): RespVo<Unit> {
        if (onflowConfig.dict.standalone) {
            // INFO: Zhouwx: 2025/9/5 单节点则直接加载
            try {
                DictLock.lock.lock()
                sysDictManager.initDict()
            } catch (e: Exception) {
                logError(e)
            } finally {
                DictLock.lock.unlock()
            }
        } else {
            // INFO: Zhouwx: 2025/9/5 多节点采用redis广播
            redisTemplate.convertAndSend(DictRedisKey.DICT_REFRESH, "refresh")
        }

        return success()
    }

    fun childrenList(qo: SysDictSearchQo, context: Context): RespVo<List<SysDictListVo>> {
        qo.parentId ?: fail(ReturnCode.LACK_PARAM, "请传入父级id")
        val findByList = sysDictMapper.findByList(qo)
        return success(findByList.dict())
    }

// [[ OnflowGenerator Range (- selectFunctions -) Start ]]

    fun selectCodeList(qo: SysDictSearchQo, context: Context): RespVo<List<KeyLabelValueVo>> {
        val vos = sysDictMapper.selectCodeList(qo)
        return success(vos)
    }

    fun selectNameList(qo: SysDictSearchQo, context: Context): RespVo<List<KeyLabelValueVo>> {
        val vos = sysDictMapper.selectNameList(qo)
        return success(vos)
    }
// [[ OnflowGenerator Range (- selectFunctions -) End ]]
}